/*

  Implementation of a model loader for the obj
  file format.

  @author Richard Kelley, Liesl Wigand

 */

#include <fstream>
#include <iostream> // remove for release
#include <string>
#include <vector>

#include "splitter.h"

#include "mesh.h"
#include "mesh_loader.h"

/*
  Parse a string representing a face.
*/
void parseFace(const std::string& s, std::vector<int>& v) {

  char buffer[11];
  int j = 0;
  for (int i = 0; i < (int)s.length(); ++i) {
    //if (s.c_str()[i] == ' ')
    //continue;
    if (s.c_str()[i] != '/') {
      buffer[j++] = s.c_str()[i];
    } else if (j > 0) {
      buffer[j] = 0;
      //printf("number: %s\n", buffer);
      v.push_back(atoi(buffer));
      j = 0;
    }
  }

  // push back the last number
  buffer[j] = 0;
  v.push_back(atoi(buffer));
}

blackjack::MeshLoader::MeshLoader() {

}

bool blackjack::MeshLoader::loadFromFile(Mesh *target, std::string fileName) {

  // open the file.
  std::ifstream file;
  file.open(fileName.c_str());

  if (!file.good())
      qDebug() << fileName.c_str();
  else
      qDebug() << "All's well";

  // process each line.
  std::string currentLine;
  std::vector<std::string> coords;
  while(getline(file, currentLine)) {
    //std::cout << "Current line: " << currentLine << std::endl;

    // skip comments
    if (currentLine[0] == '#') {
      //printf("skipping comment.\n");
      continue;
    }

    // tokenize the line
    split(currentLine, ' ', coords);

    // process mtllib declaration
    if (coords[0] == "mtllib") {

    }

    // process a vertex
    if (coords[0] == "v") {
      //std::cout << "Processing a vertex." << std::endl;
      Vertex *v = new Vertex;
      //std::cout << "vertex: " << v << std::endl;
      v->x = atof(coords[1].c_str());
      v->y = atof(coords[2].c_str());
      v->z = atof(coords[3].c_str());
      v->w = 1.0;

      //std::cout << "Adding vertex: " << v->x << " " << v->y << " " << v->z << std::endl;

      target->addVertex(v);

    }

    // process a texture coordinate
    if (coords[0] == "vt") {

    }

    // process a vertex normal
    if (coords[0] == "vn") {
      Vertex *v = new Vertex;
      v->x = atof(coords[1].c_str());
      v->y = atof(coords[2].c_str());
      v->z = atof(coords[3].c_str());
      v->w = 1.0;

      target->addVertexNormal(v);
    }

    // process a usemtl declaration
    if (coords[0] == "usemtl") {

    }

    // process smooth shading
    if (coords[0] == "s") {
      if (coords[1] == "1") {
        target->setSmooth(true);
      } else {
        target->setSmooth(false);
      }
    }

    // process a face
    if (coords[0] == "f") {
      std::vector<int> vertexCoords;
      std::vector<int> textureCoords;
      std::vector<int> normalCoords;

      std::vector<int> term;
      std::vector<int> term1;
      std::vector<int> term2;

      parseFace(coords[1], term);
      parseFace(coords[2], term1);
      parseFace(coords[3], term2);

      if (term.size() == 2) {
        // handle the vertex information
        int *f = (int*) malloc(sizeof(int) * 6);
        f[0] = term[0];
        f[1] = term1[0];
        f[2] = term2[0];
        f[3]=term[1];
        f[4]=term1[1];
        f[5]=term2[1];
        //qDebug()<<"vNorm "<<f[3]<<' '<<f[4]<<' '<<f[5];

        // false because we're not checking orientation right now.
        target->addFace(f, false);

        // handle the normal information
        // TODO
      } else if (term.size() == 3) {
        // handle the vertex information
        int *f = (int*) malloc(sizeof(int) * 6);
        f[0] = term[0];
        f[1] = term1[0];
        f[2] = term2[0];
        f[3]=term[2];
        f[4]=term1[2];
        f[5]=term2[2];
        //qDebug()<<"vNorm "<<f[3]<<' '<<f[4]<<' '<<f[5];

        // false because we're not checking orientation right now.
        target->addFace(f, false);

        // handle the texture information
        // handle the normal information
      } else {

      }


      term.clear();

    }

    coords.clear();

  }

  // close the file
  file.close();

  return true;
}
